home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / plotting / pcgplots / cgmio.cpp < prev    next >
C/C++ Source or Header  |  1992-04-24  |  39KB  |  1,395 lines

  1. // C++ .cc file for gplot, CGM-specific I/O  and parsing -*-c++-*-
  2. // copyright Phil Andrews, Pittsburgh Supercomputing Center, 1992
  3. // all rights reserved
  4. #ifdef macintosh
  5. #  include <errors.h>
  6. #endif
  7. #include <ctype.h>
  8. #include <stdio.h>
  9. #include <values.h>
  10. #include "cgm.h"
  11. #include "cgmio.h"
  12. #ifndef _toupper
  13. #define _toupper(c) ((c) -'a'+'A')
  14. #endif
  15. ////
  16. // error call
  17. ////
  18. extern void myError(const char *inMsg, const char *inMsg2=NULL,
  19.             int severity=1);
  20. #ifdef macintosh
  21.  #pragma segment CIO1
  22. #endif
  23. // inititalization needed  for some compilers
  24. int cgmInput::beginPictureIndex = 0;
  25. int cgmInput::endMetafileIndex = 0;
  26. ////
  27. // basic cgm input
  28. ////
  29. const int cgmInput::noErrors = 1;
  30. const int cgmInput::noSep = 1<<1;
  31. const int cgmInput::skipParen = 1<<2;
  32. ////
  33. //initialize constants
  34. ////
  35.  
  36.  
  37.  
  38. void cgmInput::initialize()
  39. {
  40.   // do we need to initialize the name array ?
  41.   if (!cgmNameArray) initNameArray();
  42.   // initialize other pointers
  43.   vdcTypeCmd = NULL;
  44.   intPrecCmd = NULL;
  45.   realPrecCmd = NULL;
  46.   indexPrecCmd = NULL;
  47.   defColrPrec.maxInt = 255;
  48.   defColrPrec.noBytes = 1;
  49.   defColrIndexPrec.maxInt = 255;
  50.   defColrIndexPrec.noBytes = 1;
  51.   colrPrecCmd = NULL;
  52.   colrIndexPrecCmd = NULL;
  53.   vdcIntPrecCmd = NULL;
  54.   defVdcIntPrecCmd = NULL;
  55.   vdcRealPrecCmd = NULL;
  56.   defVdcRealPrecCmd = NULL;
  57.   inputError = 0;
  58. }
  59. ////
  60. // index the metafile
  61. ////
  62. void cgmInput::makeIndex(cgmMetafile *inMF)
  63. {
  64.   if (!inMF->firstPic) return; // no pictures
  65.   cgmBeginPicture *myBeginPic;
  66.   cgmPicture *lastPic, *currPic = NULL;
  67.   ////
  68.   // mark our spot
  69.   filePos savePos = pos();
  70.   ////
  71.   // go to the beginning
  72.   goTo(inMF->start());
  73.   lastPic = inMF->firstPic;
  74.   ////
  75.   // find all of the begin picture commands (already have at least first one)
  76.   int noPics = 0;
  77.   while (getCmd() && !sameCmd(cgmNameArray[endMetafileIndex])) {
  78.     if (sameCmd(cgmNameArray[beginPictureIndex])) { // begin picture
  79.       if (noPics) { // at second one, at least
  80.     myBeginPic = new cgmBeginPicture(inMF, this);
  81.     if (!currPic) lastPic->next =
  82.       new cgmPicture(inMF, this, myBeginPic, lastPic);
  83.     lastPic = lastPic->next;
  84.       }
  85.       currPic = lastPic->next;
  86.       ++noPics;
  87.     } // begin picture
  88.   } // got a command
  89.   ////
  90.   // go back to where we began
  91.   goTo(savePos);
  92. }
  93. ////
  94. // get a direct colour (R,G,B)
  95. ////
  96. void cgmInput::getDColr(dColr &inColr)
  97. {
  98. //  for (int i=0; i<3; ++i) inColr[i] = getCD();
  99.   for (int i=0; i<3; ++i) inColr.setValue(i, getCD());
  100. }
  101. ////
  102. // get a general colour
  103. ////
  104. genColr *cgmInput::getColr(int mode, const colrValueExtent *inExtent,
  105.                  const colrTable *inTable)
  106. {
  107.   if (mode) { // r, g, b mode
  108.     int red = getCD();
  109.     int green = getCD();
  110.     int blue = getCD();
  111.     return new genColr(red, green, blue, inExtent, inTable);
  112.   } else return new genColr(getCI(), inExtent, inTable); // indexed
  113. }
  114. ////
  115. // get a single vdc measure
  116. ////
  117. vdc *cgmInput::getVdc()
  118. {
  119.   if (myVdcType()) { // real VDC
  120.     return new vdc(getVRP());
  121.   }  else { // integer VDC
  122.     return new vdc(getVIP());
  123.   }
  124. }
  125. ////
  126. // get a set of vdc points
  127. ////
  128. vdcPts *cgmInput::getVdcPts(int inNoPts)
  129. {
  130.   int maxPts = inNoPts ? inNoPts : getNoPts(); // how many would we like
  131.   int ptsGot = 0;
  132.   if (myVdcType()) { // real VDC
  133.     float *floatPtr = new float[maxPts * 2]; // real vdc
  134.     while ((ptsGot < maxPts) && getPt(floatPtr + 2 * ptsGot)) ++ptsGot;
  135.     return new vdcPts(floatPtr, ptsGot);
  136.   }  else { // integer VDC
  137.     int *intPtr = new int[maxPts * 2]; // integer vdc
  138.     while ((ptsGot < maxPts) && getPt(intPtr + 2 * ptsGot)) ++ptsGot;
  139.     return new vdcPts(intPtr, ptsGot);
  140.   }
  141. }
  142. ////
  143. // get a polygon set
  144. ////
  145. void cgmInput::polygonSet(vdcPts* &outPts, int* &outFlags)
  146. {
  147.   int maxPts = polygonSetSize(), ptsGot = 0;
  148.   outFlags = new int[maxPts];
  149.   if (myVdcType()) { // real VDC
  150.     float *floatPtr = new float[maxPts * 2]; // real vdc
  151.     while ((ptsGot < maxPts) && getPt(floatPtr + 2 * ptsGot)) {
  152.       outFlags[ptsGot] = getType(cgmPolygonSet::typeList,
  153.                  cgmPolygonSet::typeListSize);
  154.       ++ptsGot;
  155.     }
  156.     outPts = new vdcPts(floatPtr, ptsGot);
  157.   }  else { // integer VDC
  158.     int *intPtr = new int[maxPts * 2]; // integer vdc
  159.     while ((ptsGot < maxPts) && getPt(intPtr + 2 * ptsGot)) {
  160.       outFlags[ptsGot] = getType(cgmPolygonSet::typeList,
  161.                  cgmPolygonSet::typeListSize);
  162.       ++ptsGot;
  163.     }
  164.     outPts =  new vdcPts(intPtr, ptsGot);
  165.   }
  166. }
  167. ////
  168. // get a colour table
  169. ////
  170. colrTable *cgmInput::getColrTable(const colrValueExtent *inExtent)
  171. {
  172.   int startIndex = getCI();
  173.   int noEntries = getNoDColrs();
  174.   dColr tmpDColr; // temporary
  175.   colrTable *newTable = new colrTable(noEntries, inExtent, startIndex);
  176.   for (int i=0; i<noEntries; ++i) {
  177.     getDColr(tmpDColr);
  178.     newTable->addColr(tmpDColr);
  179.   }
  180.   return newTable;
  181. }
  182. ////
  183. // clear text input
  184. ////
  185. // the constant values for the clear info class
  186. ////
  187. const char clearInfo::termChar = ';'; // terminating character
  188. const char clearInfo::termChar1 = '/';
  189. const char clearInfo::quoteChar = '\"'; // quotation character
  190. const char clearInfo::quoteChar1 = '\'';
  191. const char clearInfo::sepChar = ' '; // separation character
  192. const char clearInfo::sepChar1 = '\011'; 
  193. const char clearInfo::sepChar2 = '\012'; 
  194. const char clearInfo::sepChar3 = '\013'; 
  195. const char clearInfo::sepChar4 = '\014'; 
  196. const char clearInfo::sepChar5 = '\015'; 
  197. const char clearInfo::sepChar6 = ','; 
  198. const char clearInfo::nullChar = '_'; // null character (ignored inside tokens)
  199. const char clearInfo::nullChar1 = '$';
  200. const char clearInfo::commentChar = '%'; // comment character
  201. ////
  202. // the clear input class
  203. ////
  204. // get one clear text command into memory
  205. #if __MSDOS__
  206. HugePt clearInput::getCmd()
  207. #else
  208. unsigned char *clearInput::getCmd()
  209. #endif
  210. {
  211.   // state of parsing
  212.   enum {normalS, quoting, spacing, commenting} myState = normalS; 
  213.   int done = 0; // have we finished ?
  214.   int endFile = 0; // ran out of input
  215.   char c; // latest character 
  216.   char lastQuote = 0; // last quotation character used
  217.   myLastPos = pos(); // mark our spot
  218.   bIndex = 0; // initialize buffer index
  219.   // now loop until done and still have input
  220. #ifdef macintosh
  221.   long char_count = 1;
  222.   while (!done && !(endFile = (FSRead(frefHand,&char_count, &c) == eofErr))) {
  223. #elif __MSDOS__
  224.   while ( !done && !(endFile = eof(frefHand))) {
  225.   read(frefHand, &c,1);
  226. #else
  227.   while (!done && !(endFile = ((c = getc(filePtr)) == EOF))) {    
  228. #endif
  229.   switch (myState) {
  230.     case commenting: // in the middle of a comment
  231.       if (isComment(c)) myState = normalS; // end of comment
  232.       break; // else ignore input for now
  233.      case quoting: // in the middle of a quote
  234.       if (c == lastQuote) myState = normalS; // end of quote
  235.       buffer[bIndex++] = c; // in any case take input
  236.       break;
  237.     case spacing: // getting spaces
  238.       if (isSep(c)) break; // no input
  239.       else myState = normalS; // fall thru to normalS state to process c
  240.     case normalS: // normalS input mode
  241.       if (isQuote(c)) { // begin quoting
  242.     myState = quoting;
  243.     lastQuote = c;
  244.       } else if (isComment(c)) { // begin a comment
  245.     myState = commenting;
  246.     break; // no input
  247.       } else if (isTerm(c)) { // finished this command
  248.     done = 1; 
  249.       } else if (isSep(c)) { // a separator
  250.     myState = spacing;
  251.     if (bIndex) { // had some real input already
  252.       c = sepChar; // standard separator character
  253.     } else break; // no leading spaces
  254.       } else if (isNull(c)) { // null character, ignore
  255.     break;
  256.       } else if (iscntrl(c)) { // control character, ignore
  257.     break;
  258.       }
  259.       else if (islower(c)) { // lower case
  260.     c = _toupper(c); // map to upper case for convenience
  261.       }
  262.       buffer[bIndex++] = c; // acceptable input
  263.     } // end of switch statement
  264.     if (bIndex >= bufferSize) { // need more memory
  265.       if (!doubleBuffer(bIndex)) {
  266.     myError("couldn't double buffer size", "aborting", 0);
  267.     return NULL;
  268.       }
  269.     }
  270.   } // end of while statement
  271.   if (endFile) return NULL; // no more input, will terminate
  272.   if (!done) { // incomplete command
  273.     bIndex = 0; // ignore this command, but continue processing
  274.   }
  275.   // normal finish
  276.   buffer[bIndex] = 0; // terminate string
  277.   return buffer; // return the parsed string
  278. }
  279. ////
  280. // match the incoming command name to the beginning of the buffer
  281. ////
  282. int clearInput::same(const char *inCmd)
  283. {
  284.   static const int caseDiff = 'A' - 'a';
  285.   int foundMatch;
  286.  
  287.   for (int i=0; (i<bIndex) && inCmd[i]; ++i) {
  288.     if (buffer[i] == inCmd[i]) continue;
  289.     if ((((int)buffer[i] - inCmd[i]) == caseDiff) &&
  290.     (islower(inCmd[i]))) continue;
  291.     if (((inCmd[i] - (int) buffer[i]) == caseDiff) &&
  292.     (isupper(inCmd[i]))) continue;
  293.      return 0; // no match
  294.   }
  295.   // match if got to end of inCmd, nothing useful left in buffer
  296.   foundMatch = (!inCmd[i]) && !isalnum(buffer[i]);
  297.   if (foundMatch) { // skip over the command name
  298.     aIndex = i;
  299.   }
  300.   return foundMatch;
  301. }
  302. // figure out how many points we have coming
  303. // somewhat simple minded, but should give an upper bound
  304. int clearInput::getNoPts()
  305. {
  306.   int noVDC = 0; long tIndex = aIndex;
  307.   enum {between, inNumber} myState = between;
  308.   
  309.   while ((tIndex < bIndex) && (!isTerm(buffer[tIndex]))) { // loop thru input
  310.     if (isSep(buffer[tIndex]) || (buffer[tIndex] == '(')
  311.     || (buffer[tIndex] == ')')) { // not in a number
  312.     myState = between; // mark state
  313.     } else if (myState == between) { // entering a number
  314.       myState = inNumber;
  315.       ++noVDC;
  316.     }
  317.     ++tIndex;
  318.   } // end of input
  319.   return (noVDC + 1) / 2;
  320. }
  321. // figure out how many points in a polygon set
  322. int clearInput::polygonSetSize()
  323. {
  324.   return (getNoTokens() + 2) / 3;
  325. }
  326. // figure out how many tokens we have coming
  327. int clearInput::getNoTokens()
  328. {
  329.   int noTokens = 0; long tIndex = aIndex;
  330.   enum {between, inToken} myState = between;
  331.   
  332.   while ((tIndex < bIndex) && (!isTerm(buffer[tIndex]))) {
  333.     if (isSep(buffer[tIndex])) {
  334.       if (myState == inToken) {
  335.     myState = between;
  336.       }
  337.     } else if (myState == between) {
  338.       myState = inToken;
  339.       ++noTokens;
  340.     }
  341.     ++tIndex;
  342.   }
  343.   return noTokens;
  344. }
  345. ////
  346. // get an integer point
  347. ////
  348. int clearInput::getPt(int *outArray)
  349. {
  350.   int useParen;
  351.   while ((aIndex < bIndex) && isSep(buffer[aIndex])) ++aIndex; // skip seps
  352.  
  353.   if ((useParen = (buffer[aIndex] == '('))) ++aIndex; // using parentheses
  354.   outArray[0] = getInt(); // x
  355.   outArray[1] = getInt(); // y
  356.   while ((aIndex < bIndex) && isSep(buffer[aIndex])) ++aIndex; // skip seps
  357.   if (useParen && (buffer[aIndex] == ')')) ++aIndex; // matching parenthesis
  358.   return inputError ? (inputError = 0), 0 : 1;
  359. }
  360. ////
  361. // get a real point
  362. ////
  363. int clearInput::getPt(float *outArray)
  364. {
  365.   int useParen;
  366.   while ((aIndex < bIndex) && isSep(buffer[aIndex])) ++aIndex; // skip seps
  367.  
  368.   if ((useParen = (buffer[aIndex] == '('))) ++aIndex; // using parentheses
  369.   outArray[0] = getVRP(); // x
  370.   outArray[1] = getVRP(); // y
  371.   while ((aIndex < bIndex) && isSep(buffer[aIndex])) ++aIndex; // skip seps
  372.   if (useParen && (buffer[aIndex] == ')')) ++aIndex; // matching parenthesis
  373.   return inputError ? (inputError = 0), 0 : 1;
  374. }
  375. ////
  376. // grab a string from the input, make memory for it and return a pointer
  377. ////
  378. char *clearInput::getString(int &outSize)
  379. {
  380.   char lastQuote, *newPtr;
  381.   int stringSize;
  382.  
  383.   // skip over separators
  384.   while (isSep(buffer[aIndex]) && (aIndex < bIndex)) ++aIndex;
  385.   if (aIndex >= bIndex) {
  386.     myError("couldn't find string");
  387.     outSize = 0;
  388.     return NULL;
  389.   }
  390.   if (!isQuote(buffer[aIndex])) {
  391.     myError("couldn't find quotation mark");
  392.     outSize = 0;
  393.     return NULL;
  394.   }
  395.   lastQuote = buffer[aIndex++];
  396.   for (stringSize = 0; ((aIndex + stringSize) < bIndex) &&
  397.        (lastQuote != buffer[aIndex + stringSize]); ++stringSize);
  398.   if (lastQuote != buffer[aIndex + stringSize]) {
  399.     myError("couldn't find end of quote");
  400.     outSize = 0;
  401.     return NULL;
  402.   }
  403.   newPtr = new char[stringSize + 1];
  404.   for (int i=0; i < stringSize; ++i) newPtr[i] = buffer[aIndex + i];
  405.   newPtr[i] = 0;
  406.   aIndex += stringSize + 1; // 1 for the closing quote
  407.   outSize = stringSize;
  408.   return newPtr;     
  409. }
  410. ////
  411. // basic cgm output
  412. ////
  413. // polygon set
  414. ////
  415. int cgmOutput::polygonSet(const vdcPts *inPts, const int *inFlags)
  416. {
  417.   if (!inPts || !inFlags) {
  418.     myError("no input for cgmOutput::polygonSet");
  419.     return 1;
  420.   }
  421.   vdc *myVdc;
  422.   for (int i=0; i<inPts->no(); ++i) {
  423.     myVdc = inPts->newVdc(2*i);
  424.     outVdc(myVdc);
  425.     delete myVdc;
  426.     myVdc = inPts->newVdc(2*i + 1);
  427.     outVdc(myVdc);
  428.     delete myVdc;
  429.     outType(cgmPolygonSet::typeList, inFlags[i]);
  430.   }
  431.   return 1;
  432. }
  433. ////
  434. // clear text output
  435. ////
  436. int clearOutput::startCmd(baseCGM *inCGM) // start outputting the command
  437. {
  438.   return outS(inCGM->cgmName());
  439. }
  440. int clearOutput::endCmd() // end the command
  441. {
  442.   return outC(termChar) && endLine();
  443. }
  444. int clearOutput::outString(const char *inString) // output a CGM string
  445. {
  446.   return outSep() && outC(quoteChar) && outS(inString) &&
  447.     outC(quoteChar);
  448. }
  449. // output one of a list of types
  450. int clearOutput::outType(const char **inList, int inValue)
  451. {
  452.   return outSep() && outS(inList[inValue]);
  453. }
  454. ////
  455. // input one of a list of types, assume both are in upper case
  456. ////
  457. int clearInput::getType(const char **inList, int listSize)
  458. {
  459.   // skip over separators
  460.   while (isSep(buffer[aIndex]) && (aIndex < bIndex)) ++aIndex;
  461.   if (aIndex >= bIndex) {
  462.     myError("couldn't find type");
  463.     return 0;
  464.   }
  465.   for (int i=0; i<listSize; ++i) {
  466.     for (int j=0; (aIndex < bIndex) && inList[i][j] &&
  467.      (inList[i][j] == buffer[aIndex + j]); ++j);
  468.     if (!inList[i][j] && !isalnum(buffer[aIndex + j])) { // found match
  469.       aIndex += j;
  470.       return i;
  471.     }
  472.   }
  473.   myError("couldn't match type ", (char *)buffer + aIndex);
  474.   return 0;
  475. }
  476. ////
  477. // get an integer precision
  478. ////
  479. void clearInput::getIntPrec(intPrec *inPrec)
  480. {
  481.   inPrec->minInt = getInt();
  482.   inPrec->maxInt = getInt();
  483.   inPrec->noBytes = 0;  
  484. }
  485. ////
  486. // get an unsigned integer precision
  487. ////
  488. void clearInput::getIntPrec(uIntPrec *inPrec)
  489. {
  490.   inPrec->maxInt = getInt();
  491.   inPrec->noBytes = 0;  
  492. }
  493. ////
  494. // get a real precision
  495. ////
  496. void clearInput::getRealPrec(realPrec *inPrec)
  497. {
  498.   inPrec->minReal = getReal();
  499.   inPrec->maxReal = getReal();
  500.   inPrec->noDigits = getInt();
  501.   inPrec->format = 0;
  502.   inPrec->expPart = 0;
  503.   inPrec->fractPart = 0;
  504. }
  505. // put an unsigned integer precision
  506. int clearOutput::outIntPrec(uIntPrec *inPrec)
  507. {
  508.   outInt(inPrec->maxInt);
  509.   return 1;
  510. }
  511. // put an integer precision
  512. int clearOutput::outIntPrec(intPrec *inPrec)
  513. {
  514.   outInt(inPrec->minInt);
  515.   outInt(inPrec->maxInt);
  516.   return 1;
  517. }
  518. // put a real precision
  519. int clearOutput::outRealPrec(realPrec *inPrec)
  520. {
  521.   outReal(inPrec->minReal);
  522.   outReal(inPrec->maxReal);
  523.   outInt(inPrec->noDigits);
  524.   return 1;
  525. }
  526. // get a real number
  527. float clearInput::getReal()
  528. {
  529.   const int noPowers = 21; // should be enough
  530.   static float powers[noPowers] = {1., 10., 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
  531.                    1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14,
  532.                    1e15, 1e16, 1e17, 1e18, 1e19, 1e20};
  533.  
  534.   int i;
  535.   float fractPart = 0;
  536.   int intPart = getInt(noErrors); // get the leading integer, may not exist
  537.   float ret;
  538.   if (buffer[aIndex] == '.') {
  539.     ++aIndex; // skip the period
  540.     for (i=0; isdigit(buffer[aIndex + i]); ++i); // how many digits to come
  541.     ////
  542.     // renormalize the fractional part
  543.      if (i && (fractPart = getLongDecimal())) { // have a non-zero fraction
  544.       if (i<noPowers) { // easy case
  545.     fractPart /= powers[i];
  546.       } else { // maybe on some machine of the future
  547.     for (; i; --i) fractPart /= 10.0; // must be real, ULTRIX C bug
  548.       }
  549.     }
  550.   }
  551.   ret = (intPart < 0) ? intPart - fractPart : intPart + fractPart;
  552.   ////
  553.   // do we have an exponent ?
  554.   if (buffer[aIndex] == 'E') { // scaled number
  555.     int exponent = getInt();
  556.      if (exponent < 0) {
  557.       if (exponent < noPowers) ret /= powers[exponent];
  558.       else for (i=0; i>exponent; --i) ret /= 10.0;
  559.     } else if (exponent > 0) {
  560.       if (exponent < noPowers) ret *= powers[exponent];
  561.       else for (i=0; i<exponent; ++i) ret *= 10.0;
  562.      }
  563.   }
  564.   // all done
  565.   return ret;
  566. }
  567. ////
  568. // get a cell array
  569. ////
  570. cellArray *clearInput::getCellArray(int inColMode,
  571.                   const colrValueExtent *inExtent,
  572.                   const colrTable *inTable)
  573. {
  574.   const int noPrec = 6;
  575.   static const unsigned int precValues[noPrec] = {1, 2, 4, 8, 16, 24};
  576.   long i;
  577.   vdcPts *myPts = getVdcPts(3);
  578.   int nx = getInt();
  579.   int ny = getInt();
  580.   unsigned int localColrPrec = getE(); // local colour precision
  581.   if (!localColrPrec) localColrPrec = colrPrec().maxInt; // use default
  582.   ////
  583.   // will encode in binary format, find the corresponding precision
  584.   for (i=0; (i<noPrec) && (localColrPrec > ((1<<precValues[i]) - 1)); ++i);
  585.   unsigned int binaryPrec = (i<noPrec) ? precValues[i] : 32; // 32 is the max
  586.   ////
  587.   // create the cellarray
  588.   cellArray *myPtr = new cellArray(inColMode, inExtent, myPts, nx, ny,
  589.                     binaryPrec, 1, inTable);
  590.   ////
  591.   // now get the values
  592.   long noValues;
  593.   if (inColMode) { // direct colour mode
  594.      noValues = (long)3 * nx * ny;
  595.      for (i=0; i<noValues; ++i) myPtr->addValue(getInt(skipParen));
  596.   } else {
  597.      noValues = (long)nx * ny;
  598.      for (i=0; i<noValues; ++i) myPtr->addValue(getInt(skipParen));
  599.   }
  600.   ////
  601.   return myPtr;
  602. }
  603. ////
  604. // output a cell array
  605. ////
  606. int clearOutput::outCellArray(cellArray *inC)
  607. {
  608.   int ret = 1;
  609.   ret = ret && outVdcPts(inC->corners()) && outInt(inC->nx())
  610.      && outInt(inC->ny());
  611.   // get the binary precision
  612.   unsigned int binaryPrec = inC->prec();
  613.   // find the equivalent clear text precision and output it
  614.   if (binaryPrec > (8 * sizeof(unsigned int))) {
  615.     myError("unsigned int not big enough, tell Phil !");
  616.   }
  617.   unsigned int clearPrec = (unsigned int)
  618.     (((unsigned long) 1 << binaryPrec) - 1);
  619.   ret = ret && outInt(clearPrec);
  620.   // now the values
  621.   int noValues = inC->nx() * inC->ny(); // for indexed
  622.   if (inC->colMode()) noValues *= 3; // for direct
  623.   for (int i=0; i<noValues; ++i) ret = ret && outInt(inC->getValue(i));
  624.   return ret;
  625. }
  626. ////
  627. // put a direct colour (R,G,B)
  628. ////
  629. int clearOutput::outDColr(dColr &inColr)
  630. {
  631. //  return outInt(inColr[0]) && outInt(inColr[1]) && outInt(inColr[2]);
  632.   return outInt(inColr.getValue(0)) &&
  633.      outInt(inColr.getValue(1)) && outInt(inColr.getValue(2));
  634. }
  635. ////
  636. // output a general colour
  637. ////
  638. int clearOutput::outColr(genColr *inColr)
  639. {
  640.   int ret = 1;
  641.   if (inColr->type()) { // r, g, b format
  642.     for (int i=0; i<3; ++i) ret = ret && outInt(inColr->i(i));
  643.   } else ret = outInt(inColr->i());
  644.   return ret;
  645. }
  646. ////
  647. // output a colour table
  648. ////
  649. int clearOutput::outColrTable(colrTable *inTable)
  650. {
  651.   int ret = 1;
  652.   outInt(inTable->start());
  653.   for (int i=0; i<inTable->no(); ++i) ret = ret && outDColr(inTable->val(i));
  654.   return ret;
  655. }
  656. ////
  657. // output a set of defaults
  658. ////
  659. int clearOutput::outDefaults(cgmDefaults *inDefaults)
  660. {
  661.   int ret = 1;
  662.   endCmd(); // a completely separate command in this encoding
  663.   for (baseCGM *myPtr = inDefaults->contents(); myPtr; myPtr = myPtr->next) {
  664.     myPtr->cgmOut(this);
  665.   }
  666.   outS(cgmMetafileDefaultsReplacement::endName);
  667.   return ret;
  668. }
  669. ////
  670. // output a single vdc
  671. ////
  672. int clearOutput::outVdc(const vdc *inVDC)
  673. {
  674.   return (inVDC->type()) ? outReal(inVDC->f()) : outInt(inVDC->i());
  675. }
  676. ////
  677. // output a set of vdc points
  678. ////
  679. int clearOutput::outVdcPts(const vdcPts *inPts)
  680. {
  681.   int i;
  682.   if (inPts->type()) { // real
  683.     for (i = 0; (i<inPts->no()) && outReal(inPts->fx(i)) &&
  684.      outReal(inPts->fy(i)); ++i);
  685.   } else { // integer
  686.     for (i = 0; (i<inPts->no()) && outInt(inPts->ix(i)) &&
  687.      outInt(inPts->iy(i)); ++i);
  688.   }
  689.   return i >= inPts->no(); // all successful
  690. }
  691. // functions to read in a clear text integer
  692. // get an integer from the input
  693. int clearInput::getInt(int flag)
  694. {
  695.   int isNeg = 0, firstInt;
  696.   // may skip over separators
  697.   if (flag & skipParen) { // skip over parentheses
  698.     while ((isSep(buffer[aIndex]) || (buffer[aIndex] == '(')
  699.        || (buffer[aIndex] == ')')) && (aIndex < bIndex)) ++aIndex;
  700.   } else if (!(flag & noSep)) { // mustn't jump over separators
  701.     while (isSep(buffer[aIndex]) && (aIndex < bIndex)) ++aIndex;
  702.   }
  703.   if (aIndex >= bIndex) {
  704.     myError("couldn't find integer");
  705.     inputError = 1;
  706.     return 0;
  707.   }
  708.   // what's our first character ?
  709.   if (buffer[aIndex] == '-') {
  710.     isNeg = 1;
  711.     ++aIndex;
  712.   } else if (buffer[aIndex] == '+') ++aIndex;
  713.   else if (!isdigit(buffer[aIndex])) { // no digit ?, may be OK
  714.     if (!(flag & noErrors)) { // should get an integer
  715.       myError("no digits for getInt in", (char *)buffer);
  716.       myError("getInt read to", (char *)buffer + aIndex);
  717.       inputError = 1;
  718.     }
  719.     return 0; // return 0 in any case
  720.   }
  721.   // now guarranteed some digits
  722.   firstInt = getDecimal();
  723.   if (buffer[aIndex] == '#') {  // do we have a base ?
  724.     if ((firstInt >= 2) && (firstInt <= 16)) {
  725.       return (isNeg) ? - getBased(firstInt) : getBased(firstInt);
  726.     } else {
  727.       myError("illegal base");
  728.       inputError = 1;
  729.       return 0;
  730.     }
  731.   } // bare integer
  732.   return (isNeg) ? - firstInt : firstInt;
  733. }
  734. // read a simple decimal integer, assume already lined up at first digit
  735. int clearInput::getDecimal()
  736. {
  737.   int i;
  738.   long ret = 0;
  739.   while (isdigit(buffer[aIndex])) { // should work anywhere
  740.     for (i=0; (digits[i] != buffer[aIndex]); ++i); // first matching digit
  741.     ret = 10 * ret + i;
  742.     ++aIndex;
  743.   }
  744.   return (int) ret;
  745. }
  746. // read a simple long decimal integer, assume already lined up at first digit
  747. long clearInput::getLongDecimal()
  748. {
  749.   int i;
  750.   long ret = 0;
  751.   while (isdigit(buffer[aIndex])) { // should work anywhere
  752.     for (i=0; (digits[i] != buffer[aIndex]); ++i); // first matching digit
  753.     ret = 10 * ret + i;
  754.     ++aIndex;
  755.   }
  756.   return ret;
  757. }
  758. // read a based integer
  759. int clearInput::getBased(int inBase)
  760. {
  761.   static char extDigits[] =
  762.     {'0', '1', '2', '3', '4', '5', '6', '7',
  763.      '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
  764.   static const int maxExtend = sizeof(extDigits) / sizeof(extDigits[0]);
  765.   int ret = 0, i;
  766.   
  767.   // check that we have a legal base 
  768.   if ((inBase < 2) || (inBase > maxExtend)) {
  769.     myError("illegal base");
  770.     return 0;
  771.   }
  772.  
  773.   // check that we have a legit number
  774.   for (i=0; (i<inBase) && (extDigits[i] != buffer[aIndex]); ++i);
  775.   if (i>=inBase) {
  776.     myError("illegal based integer");
  777.     return 0;
  778.   }
  779.   
  780.   while (1) {
  781.     for (i=0; (i<inBase) && (extDigits[i] != buffer[aIndex]); ++i);
  782.     if (i>=inBase) { // no more digits
  783.       return ret;
  784.     } else { // more to go ?
  785.       ret = inBase * ret + i;
  786.         ++aIndex;
  787.     }
  788.   }
  789. }
  790. ////
  791. // the binary input class
  792. ////
  793. // destructor
  794. ////
  795. binaryInput::~binaryInput() {} // keep Cray CC happy
  796. ////
  797. // get one binary command into memory
  798. ////
  799. #if __MSDOS__
  800. HugePt binaryInput::getCmd()
  801. #else
  802. unsigned char *binaryInput::getCmd()
  803. #endif
  804. {
  805.   int pLen, done, bytesNeeded;
  806.   // get the next 2 non-zero bytes (skip simple, 2-byte NULLS)
  807.   do {
  808.      if (!getOffBytes(2)) {
  809.       myError("couldn't get command header");
  810.       return NULL;
  811.     }
  812.   } while (!(buffer[0] || buffer[1]));
  813.   myLastPos = pos() - 2; // mark beginning of actual command
  814.   aIndex = bIndex = 2;
  815.   ////
  816.   // get the parameter length
  817.   pLen = buffer[1] & 31;
  818.   if (pLen < 31) { // short form, buffer size is guaranteed larger
  819.     // next command must start on even boundary
  820.     bytesNeeded = (pLen % 2) ? pLen + 1 : pLen;
  821.      if (bytesNeeded && !getOffBytes(bytesNeeded, bIndex)) {
  822.         myError("couldn't get command");
  823.       return NULL;
  824.     } else {
  825.       bIndex += pLen;
  826.       return buffer;
  827.     }
  828.   }
  829.   // long form
  830.   do { // carry on until we get a terminating partition header
  831.     if (!getOffBytes(2, bIndex)) { // get the next 2 bytes
  832.       myError("couldn't get partition header");
  833.       return NULL;
  834.     }
  835.     pLen = ((buffer[bIndex] & 127) << 8) | buffer[bIndex + 1];
  836.     done = !(buffer[bIndex] & 128); // finished ?
  837.     // next command must start on even boundary
  838.     bytesNeeded = (done && ((bIndex + pLen) % 2)) ? pLen + 1 : pLen;
  839.     // may need more memory
  840.     while ((bytesNeeded + bIndex) > bufferSize) {
  841.       if (!doubleBuffer(bIndex)) return NULL;
  842.     } // get bytes, maybe overwriting partition header
  843.      if (bytesNeeded && !getOffBytes(bytesNeeded, bIndex)) {
  844.         myError("couldn't get partition");
  845.       return NULL;
  846.     }
  847.     bIndex += pLen;
  848.   } while (!done);
  849.   return buffer;
  850. }
  851. ////
  852. // grab a string from the input, make memory for it and return a pointer
  853. ////
  854. char *binaryInput::getString(int &outSize)
  855. {
  856.   char *newPtr = NULL;
  857.   int i, pLen, sIndex;
  858.   unsigned int stringSize =  (aIndex < bIndex)?  buffer[aIndex++] : 0; // first byte has initial length
  859.   if (stringSize < 255) { // simple string
  860.     newPtr = new char[stringSize + 1];
  861.     for (i=0; i < stringSize; ++i) newPtr[i] = buffer[aIndex + i];
  862.     newPtr[i] = 0;
  863.     aIndex += stringSize;
  864.     outSize = stringSize;
  865.     return newPtr;     
  866.   }
  867.   // now have complex string, get size first
  868.   int done;
  869.   stringSize = 0; // start fresh
  870.   do {
  871.     done = !(buffer[aIndex + stringSize] & 128); // finished ?
  872.     stringSize += ((buffer[aIndex + stringSize] & 127) << 8)
  873.       | buffer[aIndex + stringSize + 1];
  874.   } while (!done);
  875.   // now make the memory
  876.   newPtr = new char[stringSize + 1];
  877.   // and fill it out
  878.   sIndex = 0;
  879.   do {
  880.     done = !(buffer[aIndex] & 128); // finished ?
  881.     pLen = ((buffer[aIndex] & 127) << 8) | buffer[aIndex + 1];
  882.     aIndex += 2;
  883.     for (i=0; i<pLen; ++i) newPtr[sIndex++] = buffer[aIndex++];
  884.   } while (!done);
  885.   if (sIndex != stringSize) myError("bad string");
  886.   newPtr[sIndex]  = 0;
  887.   outSize = stringSize;
  888.   return newPtr;
  889. }
  890. ////
  891. // diagnostic
  892. ////
  893. const char *binaryInput::cmdSignature()
  894. {
  895.   static char myString[60];
  896.   sprintf(myString, "(%d, %d) = (%d, %d)", (int) buffer[0], (int) buffer[1],
  897.       bufferClass(), bufferElement());
  898.   return myString;
  899. }
  900. ////
  901. // general signed integer (assume long at least 4 bytes, may truncate)
  902. ////
  903. int binaryInput::gInt(int noBytes)
  904. {
  905.   long ret = (buffer[aIndex] & 128) ? (-1 ^ 255) | (int) buffer[aIndex++]
  906.     : buffer[aIndex++];
  907.   switch(noBytes) {
  908.   case 4:
  909.     ret = (ret<<8) | buffer[aIndex++]; // fallthru
  910.   case 3:
  911.     ret = (ret<<8) | buffer[aIndex++]; // fallthru
  912.   case 2:
  913.     ret = (ret<<8) | buffer[aIndex++]; // end
  914.   }
  915.   return (int) ret;
  916. }
  917. ////
  918. // general shifted signed integer
  919. ////
  920. int binaryInput::gShiftInt(int noBytes, int bitsRead)
  921. {
  922.   // for convenience/speed
  923.   static unsigned char bitMask[8] = {255, 127, 63, 31, 15, 7, 3, 1};
  924.   //
  925.   if ((bitsRead > 7) || (bitsRead < 0)) {
  926.     myError("illegal bitsRead");
  927.     return 0;
  928.   }
  929.   if (bitsRead == 0) return gInt(noBytes); // no shift
  930.   // span parts of noBytes + 1 bytes
  931.   //
  932.   // spans at least 2 bytes, get 'em one at a time
  933.   // first byte
  934.   // get the sign
  935.   long ret = ((buffer[aIndex] & (1 << (7 - bitsRead))) ? -1 : 0)
  936.     << (7 - bitsRead);
  937.   // now the rest of the bits
  938.   ret = ret | (buffer[aIndex++] & bitMask[bitsRead]);
  939.   switch(noBytes) {
  940.   case 4:
  941.     ret = (ret<<8) | buffer[aIndex++]; // fallthru
  942.   case 3:
  943.     ret = (ret<<8) | buffer[aIndex++]; // fallthru
  944.   case 2:
  945.     ret = (ret<<8) | buffer[aIndex++]; // end
  946.   }
  947.   // last byte
  948.   ret = (ret << bitsRead) | (buffer[aIndex] >> (8 - bitsRead));
  949.   return ret;
  950. }
  951. ////
  952. // general unsigned integer
  953. ////
  954. unsigned int binaryInput::gUInt(int noBytes)
  955. {
  956.   unsigned long ret = buffer[aIndex++];
  957.   switch(noBytes) {
  958.   case 4:
  959.     ret = (ret<<8) | (buffer[aIndex++] & 255); // fallthru
  960.   case 3:
  961.     ret = (ret<<8) | (buffer[aIndex++] & 255); // fallthru
  962.   case 2:
  963.     ret = (ret<<8) | (buffer[aIndex++] & 255); // end
  964.   }
  965.   return (unsigned int) ret;
  966. }
  967. ////
  968. // figure out how many points we have coming
  969. ////
  970. int binaryInput::getNoPts()
  971. {
  972.   if (aIndex >= bIndex) {
  973.     myError("no Pts to get");
  974.     return 0;
  975.   }
  976.   // each vdc uses an even number of bytes, 2 vdc's per point (8/2 = 4)
  977.   if (myVdcType()) { // real vdc's
  978.     return ((bIndex - aIndex) * 4)  /
  979.       (vdcRealPrec().expPart + vdcRealPrec().fractPart);
  980.   } else return (bIndex - aIndex) / (2 * vdcIntPrec().noBytes);
  981. }
  982. ////
  983. // figure out how many points we have in a polygon set
  984. ////
  985. int binaryInput::polygonSetSize()
  986. {
  987.   if (aIndex >= bIndex) {
  988.     myError("no polygon set Pts to get");
  989.     return 0;
  990.   }
  991.   // each vdc uses an even number of bytes, 2 vdc's per point (8/2 = 4)
  992.   // the enumerated flag takes 2 bytes
  993.   if (myVdcType()) { // real vdc's
  994.     return ((bIndex - aIndex) * 4)  /
  995.       (vdcRealPrec().expPart + vdcRealPrec().fractPart + 8);
  996.   } else return (bIndex - aIndex) / (2 * vdcIntPrec().noBytes + 2);
  997. }
  998. ////
  999. // get one real vdc pt
  1000. ////
  1001. int binaryInput::getPt(float *inF)
  1002. {
  1003.   if (aIndex >= bIndex) return 0;
  1004.   inF[0]=getVRP();
  1005.   if (aIndex >= bIndex) return 0;
  1006.   inF[1]=getVRP();
  1007.   return (aIndex > bIndex) ? 0 : 1;
  1008. }
  1009. ////
  1010. // get one integer vdc pt
  1011. ////
  1012. int binaryInput::getPt(int *inI)
  1013. {
  1014.   if (aIndex >= bIndex) return 0;
  1015.   inI[0]=getVIP();
  1016.   if (aIndex >= bIndex) return 0;
  1017.   inI[1]=getVIP();
  1018.   return (aIndex > bIndex) ? 0 : 1;
  1019. }
  1020. ////
  1021. // general fixed point real
  1022. ////
  1023. float binaryInput::gFX(realPrec &inPrec)
  1024. {
  1025.   double expPart = gInt(inPrec.expPart/8);
  1026.   double fractPart = gUInt(inPrec.fractPart/8);
  1027.   float ret = expPart + fractPart / ((long) 1 << inPrec.fractPart);
  1028.   return ret;
  1029. }
  1030. ////
  1031. // general floating point real
  1032. ////
  1033. float binaryInput::gFP(realPrec &inPrec)
  1034. {
  1035.   static double p149 = 1, p23 = 1, p1074, p52;
  1036.   double dfract;
  1037.   unsigned int exponent;
  1038.   unsigned long fract;
  1039.   float ret;
  1040.   int i;
  1041.   if (p149 == 1) for (i=0; i<149; ++i) p149 *= 2.0; // initialize
  1042.   if (p23 == 1) for (i=0; i<23; ++i) p23 *= 2.0; // initialize
  1043.   if (p1074 == 1) for (i=0; i<1074; ++i) p1074 *= 2.0; // initialize
  1044.   if (p52 == 1) for (i=0; i<p52; ++i) p52 *= 2.0; // initialize
  1045.  
  1046.   int signBit = (buffer[aIndex] >> 7) & 1; // is this negative ?
  1047.   // which precision is this ?
  1048.   switch (inPrec.fractPart + inPrec.expPart) {
  1049.   case 32: // 32 bit precision
  1050.     // get the exponent
  1051.      exponent = ((buffer[aIndex] & 127) << 1) + ((buffer[aIndex + 1] >> 7) & 1);
  1052.     // get the fractional part
  1053.      fract = ((unsigned long)(buffer[aIndex + 1] & 127) << 16) +
  1054.                 ((unsigned long)buffer[aIndex + 2] << 8)
  1055.       + buffer[aIndex + 3];
  1056.      // step forward the pointer before we forget
  1057.     aIndex += 4;
  1058.     // check for special cases
  1059.     if (exponent == 255) {
  1060.       if (fract == 0) { // big number
  1061.     return (signBit) ? -MAXFLOAT : MAXFLOAT;
  1062.       } else { // screwed up
  1063.     myError("undefined IEEE number");
  1064.     return 0;
  1065.       }
  1066.     } else if (exponent == 0) {
  1067.       if (fract == 0) return 0;
  1068.       else return (signBit) ? -fract / p149 : fract / p149; // fract / 2^149
  1069.     } else { // normal number
  1070.       ret = 1 + fract / p23;
  1071.       if (exponent < 127) for (i=0; i<(127-exponent); ++i) ret /= 2.0;
  1072.       else if (exponent > 127) for (i=0; i<(exponent-127); ++i) ret *= 2.0;
  1073.       return (signBit) ? -ret : ret;
  1074.     }
  1075.      break;
  1076.   case 64: // 64 bit precision  !!! not for PC
  1077.     exponent = ((buffer[aIndex] & 127) << 4) + ((buffer[aIndex+1] >> 4) & 15);
  1078.     // fractional [part might not fit in a long
  1079.     dfract = buffer[aIndex + 1] & 15;
  1080.     for (i=2; i<8; ++i) {
  1081.       dfract *= 256.0;
  1082.       dfract += buffer[aIndex + i];
  1083.     }
  1084.     // step forward the pointer before we forget
  1085.     aIndex += 8;
  1086.     if (exponent == 2047) {
  1087.       if (fract == 0) { // big number
  1088.     return (signBit) ? -MAXFLOAT : MAXFLOAT;
  1089.       } else { // screwed up
  1090.     myError("undefined IEEE number");
  1091.     return 0;
  1092.       }
  1093.     } else if (exponent == 0) {
  1094.       if (fract == 0) return 0;
  1095.       else return (signBit) ? -fract / p1074 : fract /p1074; // fract / 2^1074
  1096.     } else { // normal number
  1097.       ret = 1 + dfract / p52;
  1098.       if (exponent < 1023) {
  1099.     for (i=0; i<(1023 - exponent); ++i) ret /= 2.0;
  1100.       } else if (exponent > 1023) {
  1101.     for (i=0; i<(exponent - 1023); ++i) ret *= 2.0;
  1102.     return (signBit) ? -ret : ret;
  1103.       } else return 0; // screwed up
  1104.     }
  1105.     break;
  1106.   }
  1107.   return 0; // for safety
  1108. }
  1109. ////
  1110. // get a real precision
  1111. ////
  1112. void binaryInput::getRealPrec(realPrec *inPrec)
  1113. {
  1114.   char myString[60];
  1115.   int format = getE();
  1116.   int expPart = getInt();
  1117.   int fractPart = getInt();
  1118.   // check for legality
  1119.   if ((((fractPart + expPart) != 32) && ((fractPart + expPart) != 64)) ||
  1120.       ((format != 0) && (format != 1)) ||
  1121.       ((format == 0) && ((fractPart != 9) && (fractPart != 23))) ||
  1122.       ((format == 1) && ((fractPart != 16) && (fractPart != 32)))) {
  1123.     sprintf(myString, "(%d, %d, %d)", format, expPart, fractPart);
  1124.     myError("illegal binary real precision", myString);
  1125.     return;
  1126.   }
  1127.   ////
  1128.   inPrec->format = format;
  1129.   inPrec->expPart = expPart;
  1130.   inPrec->fractPart = fractPart;
  1131.   inPrec->minReal = - 1 << expPart; // guess
  1132.   inPrec->maxReal = 1 << expPart; // guess
  1133. }
  1134. ////
  1135. // NCAR specific input
  1136. ////
  1137. // initialization
  1138. ////
  1139. void NCARInput::initialize()
  1140. {
  1141.   if (!fillLocalBuffer()) myError("couldn't get first NCAR block");
  1142. }
  1143. ////
  1144. // get some bytes
  1145. ////
  1146. int NCARInput::getOffBytes(unsigned int noBytes, unsigned long offset)
  1147. {
  1148.   for (int i=0; i<noBytes; ++i) {
  1149.     while ((endIndex <= startIndex) && fillLocalBuffer()); // may need bytes
  1150.     if (endIndex <= startIndex) {
  1151.       myError("couldn't get NCAR data");
  1152.       return 0;
  1153.     } else buffer[offset + i] = localBuffer[startIndex++];
  1154.   }
  1155.   return 1;
  1156. }
  1157. ////
  1158. // fill the local buffer
  1159. ////
  1160. int NCARInput::fillLocalBuffer()
  1161. {
  1162.   if (!getBytes(NCARSIZE, localBuffer)) {
  1163.     myError("couldn't get NCAR block");
  1164.     return 0;
  1165.   }
  1166.   startIndex = 4; // start of real data
  1167.   endIndex = startIndex + ((localBuffer[0] << 8) | (localBuffer[1] & 255));
  1168.   if (endIndex % 2) ++endIndex; // sometimes NCAR doesn't include pad byte
  1169.   if (endIndex > NCARSIZE) {
  1170.     char myString[20];
  1171.     sprintf(myString, "%d bytes", endIndex - startIndex);
  1172.     myError("too many bytes in NCAR header", myString);
  1173.     return 0;
  1174.   } else return 1;
  1175. }
  1176. ////
  1177. // get a cell array
  1178. ////
  1179. cellArray *binaryInput::getCellArray(int inColMode,
  1180.                      const colrValueExtent *inExtent,
  1181.                      const colrTable *inTable)
  1182. {
  1183.   char myString[60];
  1184.   long i;
  1185.   vdcPts *myPts = getVdcPts(3);
  1186.   int nx = getInt();
  1187.   int ny = getInt();
  1188.   unsigned int localColrPrec = getE(); // local colour precision
  1189.   if (!localColrPrec) localColrPrec = colrPrec().noBytes * 8; // use default
  1190.   ////
  1191.   // create the cellarray
  1192.   cellArray *myPtr = new cellArray(inColMode, inExtent, myPts, nx, ny,
  1193.                     localColrPrec, 1, inTable);
  1194.   // what mode is this ?
  1195.   int repMode = getE();
  1196.   ////
  1197.   // now get the values
  1198.   int valSize = (inColMode) ? 3 : 1;
  1199.   int valBits = valSize * localColrPrec;
  1200.   int noValues = valSize * nx;
  1201.   int rowSize = 2 * ((noValues * localColrPrec + 15) / 16); // padded
  1202.   if (repMode) { // packed list
  1203.      for (i=0; i<ny; ++i) {
  1204.         if ((aIndex + rowSize) > bIndex) {
  1205.     myError("not enough bytes for cell array");
  1206.     break;
  1207.         }
  1208.         // add a complete row
  1209.         myPtr->addValues(&buffer[aIndex], 0, noValues);
  1210.         aIndex += rowSize;
  1211.      }
  1212.   } else { // run length encoded
  1213.      int runCount, valsGot, j, bitsGot;
  1214.      for (i=0; i<ny; ++i) { // rows start on a 2-byte boundary
  1215.         bitsGot = valsGot = 0;
  1216.         while (valsGot < nx) {
  1217.     runCount = getShiftInt(bitsGot); // increases aIndex
  1218.     if (((runCount + valsGot) > nx) || (runCount < 0)) {
  1219.       sprintf(myString, "%d, x = %d, nx = %d, y = %d, ny = %d",
  1220.           runCount, valsGot, nx, i, ny);
  1221.       myError("illegal runcount in cell array", myString);
  1222.       return myPtr;
  1223.     } // else OK, replicate value
  1224.     for (j=0; j<runCount; ++j)
  1225.       myPtr->addValues(&buffer[aIndex], bitsGot, valSize);
  1226.     valsGot += runCount;
  1227.     bitsGot += valBits;
  1228.     if (bitsGot > 7) { // step forward the byte index
  1229.       aIndex += bitsGot / 8;
  1230.       bitsGot = bitsGot % 8;
  1231.     }
  1232.         }
  1233.         if (aIndex > bIndex) {
  1234.     myError("not enough bytes for run length encoding");
  1235.     return myPtr;
  1236.         }
  1237.         if (bitsGot) ++aIndex; // start at a clean byte
  1238.         if (aIndex % 2) ++aIndex; // pad at end of rows
  1239.      }
  1240.   }
  1241.   ////
  1242.   return myPtr;
  1243. }
  1244. #ifdef macintosh
  1245.   #pragma segment CIO2
  1246. #endif
  1247. ////
  1248. // parsing initialization
  1249. ////
  1250. // set the parser's pointer
  1251. ////
  1252. cgmNameNew *cgmInput::cgmNameArray = NULL;
  1253. ////
  1254. // add new classes to this array later so that the parser knows about them
  1255. ////
  1256. // define an INITMACRO set up for runtime initialization
  1257. ////
  1258. #define INITMACRO(inName) \
  1259. cgmNameArray[i].myName = &inName::myName;\
  1260. cgmNameArray[i].myClass = inName::myClass;\
  1261. cgmNameArray[i].myElement = inName::myElement;\
  1262. cgmNameArray[i].fp = inName::getNew; ++i;
  1263. ////
  1264. // now fill out the structure, either at runtime
  1265. ////
  1266. void cgmInput::initNameArray() {
  1267.   ////
  1268.   // grab some memory
  1269.   cgmNameArray = new cgmNameNew[cgmNoClasses];
  1270.   if (!cgmNameArray) myError("couldn't create parsing array", "", 0);
  1271.   int i = 0;
  1272.   ////
  1273.   // delimiters
  1274.   INITMACRO(cgmBeginMetafile)
  1275.   endMetafileIndex = i; // will need this later
  1276.   INITMACRO(cgmEndMetafile)
  1277.   beginPictureIndex = i; // will need this later
  1278.   INITMACRO(cgmBeginPicture)
  1279.   INITMACRO(cgmBeginPictureBody)
  1280.   INITMACRO(cgmEndPicture)
  1281.   // metafile descriptors
  1282.   INITMACRO(cgmMetafileVersion)
  1283.   INITMACRO(cgmMetafileDescription)
  1284.   INITMACRO(cgmVdcType)
  1285.   INITMACRO(cgmIntegerPrec)
  1286.   INITMACRO(cgmRealPrec)
  1287.   INITMACRO(cgmIndexPrec)
  1288.   INITMACRO(cgmColrPrec)
  1289.   INITMACRO(cgmColrIndexPrec)
  1290.   INITMACRO(cgmMaxColrIndex)
  1291.   INITMACRO(cgmColrValueExtent)
  1292.   INITMACRO(cgmMetafileElementList)
  1293.   INITMACRO(cgmMetafileDefaultsReplacement)
  1294.   INITMACRO(cgmFontList)
  1295.   INITMACRO(cgmCharacterSetList)
  1296.   INITMACRO(cgmCharacterCodingAnnouncer)
  1297.   // picture descriptors
  1298.   INITMACRO(cgmScalingMode)
  1299.   INITMACRO(cgmColrMode)
  1300.   INITMACRO(cgmLineWidthMode)
  1301.   INITMACRO(cgmMarkerSizeMode)
  1302.   INITMACRO(cgmEdgeWidthMode)
  1303.   INITMACRO(cgmVdcExtent)
  1304.   INITMACRO(cgmBackgroundColr)
  1305.   // control elements
  1306.   INITMACRO(cgmVdcInteger)
  1307.   INITMACRO(cgmVdcReal)
  1308.   INITMACRO(cgmAuxColr)
  1309.   INITMACRO(cgmTransparency)
  1310.   INITMACRO(cgmClipRect)
  1311.   INITMACRO(cgmClip)
  1312.   // graphical primitives
  1313.   INITMACRO(cgmPolyline)
  1314.   INITMACRO(cgmDisPolyline)
  1315.   INITMACRO(cgmPolymarker)
  1316.   INITMACRO(cgmText)
  1317.   INITMACRO(cgmRestrText)
  1318.   INITMACRO(cgmApndText)
  1319.   INITMACRO(cgmPolygon)
  1320.   INITMACRO(cgmPolygonSet)
  1321.   INITMACRO(cgmGDP)
  1322.   INITMACRO(cgmCellArray)
  1323.   INITMACRO(cgmRectangle)
  1324.   INITMACRO(cgmCircle)
  1325.   INITMACRO(cgmArc3Pt)
  1326.   INITMACRO(cgmArc3PtClose)
  1327.   INITMACRO(cgmArcCtr)
  1328.   INITMACRO(cgmArcCtrClose)
  1329.   INITMACRO(cgmEllipse)
  1330.   INITMACRO(cgmEllipArc)
  1331.   INITMACRO(cgmEllipArcClose)
  1332.   // attributes
  1333.   INITMACRO(cgmLineIndex)
  1334.   INITMACRO(cgmLineType)
  1335.   INITMACRO(cgmLineWidth) 
  1336.   INITMACRO(cgmLineColr) 
  1337.   INITMACRO(cgmMarkerIndex)
  1338.   INITMACRO(cgmMarkerType)
  1339.   INITMACRO(cgmMarkerSize)
  1340.   INITMACRO(cgmMarkerColr) 
  1341.   INITMACRO(cgmTextIndex)
  1342.   INITMACRO(cgmFontIndex)
  1343.   INITMACRO(cgmTextPrec)
  1344.   INITMACRO(cgmCharExpan)
  1345.   INITMACRO(cgmCharSpace)
  1346.   INITMACRO(cgmTextColr) 
  1347.   INITMACRO(cgmCharHeight)
  1348.   INITMACRO(cgmCharOri)
  1349.   INITMACRO(cgmTextPath)
  1350.   INITMACRO(cgmTextAlign)
  1351.   INITMACRO(cgmCharSetIndex)
  1352.   INITMACRO(cgmAltCharSetIndex)
  1353.   INITMACRO(cgmFillIndex)
  1354.   INITMACRO(cgmHatchIndex)
  1355.   INITMACRO(cgmPatIndex)
  1356.   INITMACRO(cgmIntStyle)
  1357.   INITMACRO(cgmFillColr)
  1358.   INITMACRO(cgmEdgeIndex)
  1359.   INITMACRO(cgmEdgeType)
  1360.   INITMACRO(cgmEdgeWidth)
  1361.   INITMACRO(cgmEdgeColr) 
  1362.   INITMACRO(cgmEdgeVis)
  1363.   INITMACRO(cgmFillRefPt)
  1364.   INITMACRO(cgmPatTable)
  1365.   INITMACRO(cgmPatSize)
  1366.   INITMACRO(cgmColrTable)
  1367.   INITMACRO(cgmASF)
  1368.   // escape element
  1369.   INITMACRO(cgmEscapeElement)
  1370.   // externals
  1371.   INITMACRO(cgmMessage)
  1372.   INITMACRO(cgmApplData)
  1373. };
  1374. #undef INITMACRO
  1375. ////
  1376. // binary output
  1377. ////
  1378. int binaryOutput::startCmd(baseCGM *inCGM) // start outputting the command
  1379. {
  1380.   return 1; // fix later
  1381. }
  1382. int binaryOutput::endCmd() // end the command
  1383. {
  1384.   return 1; // fix later
  1385. }
  1386. int binaryOutput::outString(const char *inString) // output a CGM string
  1387. {
  1388.   return 1; // fix later
  1389. }
  1390. // output one of a list of types
  1391. int binaryOutput::outType(const char **inList, int inValue)
  1392. {
  1393.   return 1; // fix later
  1394. }
  1395.